#pragma once

#include "baseWidget.h"

#include <QLayout>
#include <QWidget>
// #include <QVTKOpenGLNativeWidget.h>
#include <vtkSmartPointer.h>
#include <vtkPoints.h>
#include <vtkPolyData.h>
#include <vtkVertexGlyphFilter.h>
#include <vtkPolyDataMapper.h>
#include <vtkActor.h>
#include <vtkRenderer.h>
#include <vtkRenderWindow.h>
#include <vtkDoubleArray.h>
#include <vtkPointData.h>
#include <vtkCubeAxesActor.h>
#include <vtkProperty.h>
#include <vtkOrientationMarkerWidget.h>
#include <vtkAxesActor.h>
#include <vtkCell.h>
#include <vtkPolyData.h>
#include <vtkPolyDataMapper.h>
#include <mutex>
#include <vtkCamera.h>
#include <vtkLookupTable.h>
#include <vtkScalarBarActor.h>
#include <vtkProperty2D.h>

#include <vtkAutoInit.h>
VTK_MODULE_INIT(vtkRenderingOpenGL2);
VTK_MODULE_INIT(vtkInteractionStyle);
VTK_MODULE_INIT(vtkRenderingFreeType);
VTK_MODULE_INIT(vtkRenderingVolumeOpenGL2);

#include "newVTKOpenGLWidget.h"
#include "Json.h"
#include "singleton.h"

#define POINTSNUM           80000
#define SAMPLESTRIDE        2
#define DISTANCE            5000
#define CAMERA_DISTANCE     3

#define VTK_P(className) vtkSmartPointer<className>

class Show3D : public BaseWidget
{
public:
    enum class ViewPos
    {
        Forward = 0,
        Down,
        Left
    };

public:
    Show3D(QWidget * parent = nullptr);
    ~Show3D();

    void __setData(std::shared_ptr<LvMat> & src, int min, int max);

    void __render();

    void setCallBackForVTK(std::function<void(void)> && cb)
    {
        m_vtkWidget->setCallBack(std::forward<std::function<void(void)>>(cb));
    }

    std::unique_ptr<LvMat> cloudPointDownSample(std::shared_ptr<LvMat> & src, int stride);

    void __saveData(const std::string & filePath);

    void ResetCamera()
    {
        m_vtkRenderer->ResetCamera();
        m_vtkRenderer->GetActiveCamera()->SetPosition(CAMERA_DISTANCE, 0, -CAMERA_DISTANCE);
        m_vtkRenderer->GetActiveCamera()->SetViewUp(1, 0, 0);
    }

    void ChangeView(ViewPos viewPos)
    {
        m_vtkRenderer->ResetCamera();
        m_vtkRenderer->GetActiveCamera()->SetViewUp(1, 0, 0);
        switch (viewPos)
        {
        case ViewPos::Forward:
            m_vtkRenderer->GetActiveCamera()->SetPosition(0, 0, -CAMERA_DISTANCE);
            break;
        case ViewPos::Down:
            // m_vtkRenderer->GetActiveCamera()->SetPosition(0, -0.5, 0);
            m_vtkRenderer->GetActiveCamera()->SetPosition(0.5, 0, -0.1);
            break;
        case ViewPos::Left:
            m_vtkRenderer->GetActiveCamera()->SetPosition(0, -CAMERA_DISTANCE, 0);
            break;
        default:
            break;
        }
    }

private:
    void drawCubePoly();

private:
    NewVTKOpenGLWidget *                    m_vtkWidget         = nullptr;
    VTK_P(vtkPoints)                        m_vtkPoints         = nullptr;
    VTK_P(vtkPolyData)                      m_vtkPolyData       = nullptr;
    VTK_P(vtkVertexGlyphFilter)             m_vtkFilter         = nullptr;
    VTK_P(vtkPolyDataMapper)                m_vtkMapper         = nullptr;
    VTK_P(vtkActor)                         m_vtkActor          = nullptr;
    VTK_P(vtkRenderer)                      m_vtkRenderer       = nullptr;
    VTK_P(vtkRenderer)                      m_vtkRendererColorB = nullptr;
    VTK_P(vtkDoubleArray)                   m_vtkDoubleArr      = nullptr;
    VTK_P(vtkCubeAxesActor)                 m_vtkCubeAxesActor  = nullptr;
    VTK_P(vtkAxesActor)                     m_vtkAxesActor      = nullptr;
    VTK_P(vtkOrientationMarkerWidget)       m_vtkOrientWidget   = nullptr;
    VTK_P(vtkLookupTable)                   m_vtkLookUpTable    = nullptr;
    VTK_P(vtkScalarBarActor)                m_vtkScalarBarActor = nullptr;
    std::mutex                              m_mutex;

    bool                                    m_isSaveFlag        = false;
    std::string                             m_filePath;

    int                                     m_pointNum;
    int                                     m_sampleStride;
};

